package com.qd.panda.etc;

import com.cdqidi.exception.ApiException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qd.panda.etc.dto.constant.EtcHttpCodeConstant;
import com.qd.panda.etc.dto.req.BaseReqDTO;
import com.qd.panda.etc.dto.req.CancelReqDTO;
import com.qd.panda.etc.dto.req.ValidateReqDTO;
import com.qd.panda.etc.dto.resp.ApplyResponseDTO;
import com.qd.panda.etc.dto.resp.AuthResponseDTO;
import com.qd.panda.etc.dto.resp.SearchResponseDTO;
import com.qd.panda.etc.dto.resp.ValidateResponseDTO;
import com.qd.panda.gas.station.base.BaseHttpResponseUtil;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;

/**
 * ETC签约和取消签约
 *
 * @author sjk
 */
@Component
@AllArgsConstructor
@Slf4j
public class EtcService {
    private static final String APP_ID = "POWER";
    private static final String SECRET_KEY = "2c98ddd97641a97e01764aceff1c4103";
    /**
     * 请求授权
     */
    private static final String APPLY_URL = "http://api.aietcp.com/extendAuth/apply";
    /**
     * 验证授权
     */
    private static final String VALIDATE_URL = "http://api.aietcp.com/extendAuth/validate";
    /**
     * 查询授权
     */
    private static final String SEARCH_URL = "http://api.aietcp.com/extendAuth/search";
    /**
     * 取消授权
     */
    private static final String CANCEL_URL = "http://api.aietcp.com/extendAuth/cancel";
    /**
     * 验证取消授权接口
     */
    private static final String VALIDATE_CANCEL_URL = "http://api.aietcp.com/extendAuth/validateCancel";
    private static final MultiValueMap<String, String> header;
    private final RestTemplate restTemplate;
    private final ObjectMapper objectMapper;

    static {
        header = new LinkedMultiValueMap<>();
        header.add("appId", APP_ID);
        header.add("secretKey", SECRET_KEY);
    }


    /**
     * 请求授权
     *
     * @param baseReqDTO 请求参数
     */
    @SneakyThrows
    public ApplyResponseDTO apply(@NotNull BaseReqDTO baseReqDTO) {
        baseReqDTO.setParkingId(APP_ID);
        log.info("请求开通ETC授权，请求参数: {}", baseReqDTO);
        HttpEntity<Object> httpEntity = new HttpEntity<>(baseReqDTO, header);
        final AuthResponseDTO authResponseDTO = build(() -> restTemplate.exchange(APPLY_URL, HttpMethod.POST, httpEntity, String.class));
        if (!authResponseDTO.isSuccess()) {
            if (!authResponseDTO.getErrCode().equals(EtcHttpCodeConstant.ETC_ERROR_702)) {
                throw new ApiException(authResponseDTO.getErrMsg());
            }
        }
        return objectMapper.readValue(authResponseDTO.getData().toString(), ApplyResponseDTO.class);
    }

    /**
     * 验证授权
     *
     * @param validateReqDTO 请求参数
     */
    @SneakyThrows
    public ValidateResponseDTO validate(@NotNull ValidateReqDTO validateReqDTO) {
        validateReqDTO.setParkingId(APP_ID);
        log.info("验证ETC授权，请求参数: {}", validateReqDTO);
        HttpEntity<Object> httpEntity = new HttpEntity<>(validateReqDTO, header);
        final AuthResponseDTO authResponseDTO = build(() -> restTemplate.exchange(VALIDATE_URL, HttpMethod.POST, httpEntity, String.class));
        if (!authResponseDTO.isSuccess()) {
            throw new ApiException(authResponseDTO.getErrMsg());
        }
        return objectMapper.readValue(authResponseDTO.getData().toString(), ValidateResponseDTO.class);
    }

    /**
     * 查询授权
     *
     * @param baseReqDTO 请求参数
     * @return 授权结果 1已授权 2未授权
     */
    @SneakyThrows
    public SearchResponseDTO search(@NotNull BaseReqDTO baseReqDTO) {
        baseReqDTO.setParkingId(APP_ID);
        log.info("查询ETC授权，请求参数: {}", baseReqDTO);
        HttpEntity<Object> httpEntity = new HttpEntity<>(baseReqDTO, header);
        final AuthResponseDTO authResponseDTO = build(() -> restTemplate.exchange(SEARCH_URL, HttpMethod.POST, httpEntity, String.class), Arrays.asList(EtcHttpCodeConstant.OK, EtcHttpCodeConstant.ETC_ERROR_705));
        if (!authResponseDTO.getErrCode().equals(HttpStatus.OK.value()) && !authResponseDTO.getErrCode().equals(EtcHttpCodeConstant.ETC_ERROR_705)) {
            throw new ApiException(authResponseDTO.getErrMsg());
        }
        if (authResponseDTO.getErrCode().equals(EtcHttpCodeConstant.ETC_ERROR_705)) {
            return null;
        }
        final JsonNode data = authResponseDTO.getData();
        return objectMapper.readValue(data.toString(), SearchResponseDTO.class);
    }

    /**
     * 取消授权
     *
     * @param cancelReqDTO 请求参数
     */
    @SneakyThrows
    public ApplyResponseDTO cancel(@NotNull CancelReqDTO cancelReqDTO) {
        cancelReqDTO.setParkingId(APP_ID);
        log.info("请求取消ETC授权，请求参数: {}", cancelReqDTO);
        HttpEntity<Object> httpEntity = new HttpEntity<>(cancelReqDTO, header);
        final AuthResponseDTO authResponseDTO = build(() -> restTemplate.exchange(CANCEL_URL, HttpMethod.POST, httpEntity, String.class));
        if (!authResponseDTO.isSuccess()) {
            //1.若用户已经注销ETC卡号，则返回code=701, message=用户已经注销ETC卡号
            //2.若用户未授权，则返回code=705, message=已授权用户不存在
            throw new ApiException(authResponseDTO.getErrMsg());
        }
        final JsonNode data = authResponseDTO.getData();
        return objectMapper.readValue(data.toString(), ApplyResponseDTO.class);
    }

    /**
     * 验证取消授权接口
     *
     * @param validateReqDTO 请求参数
     */
    @SneakyThrows
    public ValidateResponseDTO validateCancel(@NotNull ValidateReqDTO validateReqDTO) {
        validateReqDTO.setParkingId(APP_ID);
        log.info("验证取消ETC授权接口，请求参数: {}", validateReqDTO);
        HttpEntity<Object> httpEntity = new HttpEntity<>(validateReqDTO, header);
        final AuthResponseDTO authResponseDTO = build(() -> restTemplate.exchange(VALIDATE_CANCEL_URL, HttpMethod.POST, httpEntity, String.class));
        if (!authResponseDTO.isSuccess()) {
            throw new ApiException(authResponseDTO.getErrMsg());
        }
        return objectMapper.readValue(authResponseDTO.getData().toString(), ValidateResponseDTO.class);
    }

    private AuthResponseDTO build(Supplier<ResponseEntity<String>> supplier) {
        return (AuthResponseDTO) BaseHttpResponseUtil.build(supplier, this::buildAuthResponseDTO);
    }

    private AuthResponseDTO build(Supplier<ResponseEntity<String>> supplier, List<Integer> successHttpStatus) {
        return (AuthResponseDTO) BaseHttpResponseUtil.build(supplier, this::buildAuthResponseDTO, successHttpStatus);
    }

    private AuthResponseDTO buildAuthResponseDTO(JsonNode jsonNode) {
        if (null != jsonNode) {
            final JsonNode codeJsonNode = Optional.ofNullable(jsonNode.get("code")).orElseThrow(() -> new ApiException("code不存在,json：" + jsonNode));
            final JsonNode messageJsonNode = Optional.ofNullable(jsonNode.get("message")).orElseThrow(() -> new ApiException("message不存在,json：" + jsonNode));
            final JsonNode data = Optional.ofNullable(jsonNode.get("rspData")).orElseThrow(() -> new ApiException("rspData不存在,json：" + jsonNode));
            final JsonNode currentTime = Optional.ofNullable(jsonNode.get("currentTime")).orElseThrow(() -> new ApiException("currentTime不存在,json：" + jsonNode));
            AuthResponseDTO authResponseDTO = new AuthResponseDTO();
            authResponseDTO.setErrCode(codeJsonNode.intValue());
            authResponseDTO.setErrMsg(messageJsonNode.asText());
            authResponseDTO.setData(data);
            authResponseDTO.setCurrentTime(currentTime.longValue());
            return authResponseDTO;
        }
        return null;
    }
}
